﻿
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using TomanuExtensions;
using System.Linq;

namespace TomanuExtensionsTest
{
    [TestClass]
    public class DoubleExtensionsTest
    {
        [TestMethod]
        public void DoubleExtensions_Test()
        {
            DoubleExtensions_IsNumber();
            DoubleExtensions_Fraction();
            DoubleExtensions_Limit();
            DoubleExtensions_InRange();
            DoubleExtensions_MinMax();
        }

        private void DoubleExtensions_MinMax()
        {
            double[] nums = new double[] { -3, -2.9, -2, -1, -0.1, 0, 0.1, 1, 2, 2.9, 3 };

            var triples = from n1 in nums
                          from n2 in nums
                          from n3 in nums
                          select new { n1, n2, n3 };

            foreach (var triple in triples)
            {
                double min1 = DoubleExtensions.Min(triple.n1, triple.n2, triple.n3);
                double min2 = Math.Min(triple.n1, Math.Min(triple.n2, triple.n3));
                Assert.AreEqual(min2, min1);
            }

            foreach (var triple in triples)
            {
                double max1 = DoubleExtensions.Max(triple.n1, triple.n2, triple.n3);
                double max2 = Math.Max(triple.n1, Math.Max(triple.n2, triple.n3));
                Assert.AreEqual(max2, max1);
            }

            var quads = from n1 in nums
                        from n2 in nums
                        from n3 in nums
                        from n4 in nums
                        select new { n1, n2, n3, n4 };

            foreach (var quad in quads)
            {
                double min1 = DoubleExtensions.Min(quad.n1, quad.n2, quad.n3, quad.n4);
                double min2 = Math.Min(Math.Min(quad.n1, quad.n2), Math.Min(quad.n3, quad.n4));
                Assert.AreEqual(min2, min1);
            }

            foreach (var quad in quads)
            {
                double max1 = DoubleExtensions.Max(quad.n1, quad.n2, quad.n3, quad.n4);
                double max2 = Math.Max(Math.Max(quad.n1, quad.n2), Math.Max(quad.n3, quad.n4));
                Assert.AreEqual(max2, max1);
            }
        }

        private void DoubleExtensions_IsNumber()
        {
            double zero = 0;

            double[] arr = new double[] { 0 / zero, 1 / zero, -1 / zero, Double.NaN, 
                                          Double.NegativeInfinity, Double.PositiveInfinity, 
                                          Double.MinValue, Double.MaxValue, 
                                          -1.2, 0, 1.3 };
            bool[] expected = new bool[] { false, false, false, false, 
                                           false, false, true, true, 
                                           true, true, true };

            for (int i = 0; i < arr.Length; i++)
            {
                bool exp = expected[i];
                bool val = arr[i].IsNumber();
                Assert.AreEqual(exp, val);
            }
        }

        private void DoubleExtensions_Fraction()
        {
            double[] input = new double[] { -3.6, -0.4, 0, 0.2, 1.3 };
            double[] expected = new double[] { -0.6, -0.4, 0, 0.2, 0.3 };

            for (int i = 0; i < input.Length; i++)
            {
                double result = input[i].Fraction();
                Assert.IsTrue(expected[i].IsAlmostRelativeEquals(result, 1e-16));
            }
        }

        private void DoubleExtensions_Limit()
        {
            Assert.AreEqual(0.3, DoubleExtensions.Limit(0.3, 0.1, 0.4));
            Assert.AreEqual(0.1, DoubleExtensions.Limit(-0.1, 0.1, 0.4));
            Assert.AreEqual(0.4, DoubleExtensions.Limit(0.5, 0.1, 0.4));
            Assert.AreEqual(-0.3, DoubleExtensions.Limit(-0.3, -0.5, -0.1));
            Assert.AreEqual(-0.1, DoubleExtensions.Limit(1.0, -0.5, -0.1));
            Assert.AreEqual(-0.5, DoubleExtensions.Limit(-1.0, -0.5, -0.1));
        }

        private void DoubleExtensions_InRange()
        {
            Assert.AreEqual(true, DoubleExtensions.InRange(0.3, 0.1, 0.4));
            Assert.AreEqual(true, DoubleExtensions.InRange(0.1, 0.1, 0.4));
            Assert.AreEqual(false, DoubleExtensions.InRange(-0.3, 0.1, 0.4));
            Assert.AreEqual(false, DoubleExtensions.InRange(0.5, 0.1, 0.4));
            Assert.AreEqual(true, DoubleExtensions.InRange(-0.3, -0.5, -0.1));
            Assert.AreEqual(false, DoubleExtensions.InRange(1.0, -0.5, -0.1));
            Assert.AreEqual(false, DoubleExtensions.InRange(-1.0, -0.5, -0.1));
        }
    }
}
